package cn.jinzhu.netty.server;

import cn.jinzhu.netty.protocol.MessageCodecSharable;
import cn.jinzhu.netty.protocol.ProcotolFrameDecoder;
import cn.jinzhu.netty.server.handler.*;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * 服务端
 */
public class ChatServer {

    public static void main(String[] args) {
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();
        //@Sharable 可共享的handler 表示在netty中这个类可以共享给所有的NioEventLoop,说明表示可以安全 自定义协议
        MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();
        //自带日志
        LoggingHandler LOGGINGH_ANDLER = new LoggingHandler(LogLevel.DEBUG);
        ChatRequestMessageHandler chatRequestMessageHandler = new ChatRequestMessageHandler();
        LoginRequestMessageHandler loginRequestMessageHandler = new LoginRequestMessageHandler();
        GroupCreateRequestMessageHandler groupCreateRequestMessageHandler = new GroupCreateRequestMessageHandler();
//        GroupJoinRequestMessageHandler GROUP_JOIN_HANDLER = new GroupJoinRequestMessageHandler();
//        GroupMembersRequestMessageHandler GROUP_MEMBERS_HANDLER = new GroupMembersRequestMessageHandler();
//        GroupQuitRequestMessageHandler GROUP_QUIT_HANDLER = new GroupQuitRequestMessageHandler();
        GroupChatRequestMessageHandler GROUP_CHAT_HANDLER = new GroupChatRequestMessageHandler();
        QuitHandler QUIT_HANDLER = new QuitHandler();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.channel(NioServerSocketChannel.class);
            bootstrap.group(boss, worker);
            bootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
                @Override
                protected void initChannel(NioSocketChannel ch) throws Exception {




                    // 解决客户端发送过来的数据半包粘包问题  入栈处理器
                    ch.pipeline().addLast(new ProcotolFrameDecoder());
                    // 用来判断是不是 读空闲时间过长，或 写空闲时间过长  检测客户端是否异常
                    // 5s 内如果没有收到 channel 的数据，会触发一个 IdleState#READER_IDLE 事件
                    ch.pipeline().addLast(new IdleStateHandler(5, 0, 0));
                    // ChannelDuplexHandler 可以同时作为入站和出站处理器
                    ch.pipeline().addLast(new ChannelDuplexHandler() {
                        // 用来触发特殊事件
                        @Override
                        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception{
                            //强转获取事件
                            IdleStateEvent event = (IdleStateEvent) evt;
                            // 触发了读空闲事件
                            if (event.state() == IdleState.READER_IDLE) {
                                System.out.println("已经 5s 没有读到数据了");
                            ctx.channel().close();
                            }
                        }
                    });
                    //打印服务端数据 出栈处理器
                    ch.pipeline().addLast(LOGGINGH_ANDLER);
                    //将数据放入自定义协议正文中 出栈处理器
                    ch.pipeline().addLast(MESSAGE_CODEC);
                    //业务handler处理器  入栈处理器调用后会触发出栈处理器
                    // 出栈是从tail尾部向上找出栈处理器 入栈则是重头开始向下找
                    //解码之后  SimpleChannelInboundHandler  可以指定接收某个消息
                    // 有可能客户端消息类型比较多 这个可以指定接收某个类型  接收登陆类型的message
                    ch.pipeline().addLast(loginRequestMessageHandler);
                    //聊天请求接收处理器  点对点发送
                    ch.pipeline().addLast(chatRequestMessageHandler);
                    //创建群聊
                    ch.pipeline().addLast(groupCreateRequestMessageHandler);
//                    ch.pipeline().addLast(GROUP_JOIN_HANDLER);
//                    ch.pipeline().addLast(GROUP_MEMBERS_HANDLER);
//                    ch.pipeline().addLast(GROUP_QUIT_HANDLER);
                    ch.pipeline().addLast(GROUP_CHAT_HANDLER);
                    ch.pipeline().addLast(QUIT_HANDLER);
                }
            });
            //同步监听
            ChannelFuture sync = bootstrap.bind(8080).sync();
            //同步关闭
            sync.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

}
